<?php declare(strict_types=1);

/**
 * @package Reactions (Light Portal)
 * @link https://custom.simplemachines.org/index.php?mod=4244
 * @author Bugo <bugo@dragomano.ru>
 * @copyright 2023-2025 Bugo
 * @license https://spdx.org/licenses/GPL-3.0-or-later.html GPL-3.0-or-later
 *
 * @category plugin
 * @version 30.10.25
 */

namespace LightPortal\Plugins\Reactions;

use Bugo\Compat\Theme;
use Bugo\Compat\User;
use Bugo\Compat\Utils;
use LightPortal\Enums\PluginType;
use LightPortal\Plugins\Event;
use LightPortal\Plugins\Plugin;
use LightPortal\Plugins\PluginAttribute;
use LightPortal\UI\Fields\CheckboxField;
use LightPortal\Utils\Traits\HasView;

if (! defined('LP_NAME'))
	die('No direct access...');

/**
 * Generated by PluginMaker
 */
#[PluginAttribute(type: PluginType::PAGE_OPTIONS)]
class Reactions extends Plugin
{
	use HasView;

	private const PARAM = 'allow_reactions';

	public function preparePageParams(Event $e): void
	{
		$e->args->params[self::PARAM] = false;
	}

	public function validatePageParams(Event $e): void
	{
		$e->args->params[self::PARAM] = FILTER_VALIDATE_BOOLEAN;
	}

	public function preparePageFields(Event $e): void
	{
		CheckboxField::make(self::PARAM, $this->txt[self::PARAM])
			->setValue($e->args->options[self::PARAM]);
	}

	public function preparePageData(Event $e): void
	{
		[$data, $isAuthor] = [$e->args->data, $e->args->isAuthor];

		if (empty($data['options'][self::PARAM]))
			return;

		Utils::$context['can_react'] = empty($isAuthor);

		Theme::addInlineJavaScript('
			document.addEventListener("addReaction", (event) => {
				const pageUrl = ' . Utils::escapeJavaScript(LP_PAGE_URL . $data['slug']) . '
				const isComment = typeof event.detail.comment !== "undefined"
				axios.post(pageUrl + ";add_reaction", event.detail)
					.then(() => {
						isComment
						? axios
							.post(pageUrl + ";get_reactions", {
								comment: event.detail.comment
							})
							.then(response => {
								if (window.commentReactions && window.commentReactions[event.detail.comment]) {
									window.commentReactions[event.detail.comment].showButtons = false
									window.commentReactions[event.detail.comment].reactions = response.data
								}
							})
						: axios
							.get(pageUrl + ";get_reactions")
							.then(response => {
								window.pageReactions.showButtons = false
								window.pageReactions.reactions = response.data
							})
					})
			})', true);

		$reactions = json_decode($data['options'][$this->name] ?? '', true) ?? [];

		Utils::$context['reaction_buttons'] = $this->getButtons();
		Utils::$context['prepared_reactions'] = json_decode($this->getReactionsWithCount($reactions), true);

		if ($this->request()->has('get_reactions')) {
			$json = $this->request()->json();

			if (isset($json['comment'])) {
				$commentReactions = $this->getReactions($json['comment'], 'comment');
				exit($this->getReactionsWithCount($commentReactions));
			}

			exit($this->getReactionsWithCount($reactions));
		}

		if ($this->request()->has('add_reaction')) {
			$json = $this->request()->json();

			if (isset($json['reaction'])) {
				if (isset($json['comment'])) {
					$commentReactions = $this->getReactions($json['comment'], 'comment');
					$commentReactions[User::$me->id] = $json['reaction'];
					$this->addReaction($json['comment'], json_encode($commentReactions), $data['slug'], 'comment');
				} else {
					$reactions[User::$me->id] = $json['reaction'];
					$this->addReaction($data['id'], json_encode($reactions), $data['slug']);
				}
			}
		}
	}

	public function afterPageContent(): void
	{
		if (empty(Utils::$context['lp_page']['options'][self::PARAM]))
			return;

		echo $this->view('page_reactions');
	}

	public function commentButtons(Event $e): void
	{
		if (empty(Utils::$context['lp_page']['options'][self::PARAM]))
			return;

		$comment = $e->args->comment;

		$comment['can_react'] = $comment['poster']['id'] !== User::$me->id;
		$comment[$this->name] = json_decode($comment['params'][$this->name] ?? '', true) ?? [];
		$comment['prepared_reactions'] = json_decode($this->getReactionsWithCount($comment[$this->name]), true);
		$comment['prepared_buttons'] = $comment['prepared_reactions'];

		$e->args->buttons[] = $this->view('comments_reactions', compact('comment'));
	}

	private function getReactionsWithCount(array $reactions): string
	{
		return $this->response()->json(array_count_values($reactions) ?? '', JSON_FORCE_OBJECT);
	}

	private function getButtons(): array
	{
		return [
			[
				'name' => 'like',
				'title' => $this->txt['titles'][0],
				'emoji' => '👍',
			],
			[
				'name' => 'dislike',
				'title' => $this->txt['titles'][1],
				'emoji' => '👎',
			],
			[
				'name' => 'love',
				'title' => $this->txt['titles'][2],
				'emoji' => '❤️',
			],
			[
				'name' => 'laugh',
				'title' => $this->txt['titles'][3],
				'emoji' => '😆',
			],
			[
				'name' => 'sad',
				'title' => $this->txt['titles'][4],
				'emoji' => '😢',
			],
			[
				'name' => 'angry',
				'title' => $this->txt['titles'][5],
				'emoji' => '😡',
			]
		];
	}

	private function getReactions(int $id, string $entity = 'page'): array
	{
		$select = $this->sql->select()
			->from('lp_params')
			->columns(['value'])
			->where([
				'item_id' => $id,
				'type'    => $entity,
				'name'    => $this->name,
			])
			->limit(1);

		$result = $this->sql->execute($select);

		$row = $result->current();

		return json_decode($row['value'] ?? '', true) ?? [];
	}

	private function addReaction(int $id, string $value, string $slug, string $entity = 'page'): void
	{
		$replace = $this->sql->replace('lp_params')
			->setConflictKeys(['item_id', 'type', 'name'])
			->values([
				'item_id' => $id,
				'type'    => $entity,
				'name'    => $this->name,
				'value'   => $value,
			]);

		$this->sql->execute($replace);

		$this->langCache('page_' . $slug . ($entity === 'comment' ? '_comments' : ''))->forget();

		$this->response()->exit(['success' => true]);
	}
}
